package com.sd.repay.service.impl;

import com.sd.repay.common.Constants;
import com.sd.repay.dao.BaseDao;
import com.sd.repay.pojo.ScheduleJob;
import com.sd.repay.service.JobTaskService;
import com.sd.repay.task.utils.QuartzJobFactory;
import com.sd.repay.task.utils.QuartzJobFactoryDisallowConcurrentExecution;
import com.sd.repay.utils.WebUtil;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author sd
 * @Description: 定时任务管理Service
 * @date 2017年10月25日
 */
@Service
public class JobTaskServiceImpl implements JobTaskService {

    public final static Logger log = LoggerFactory.getLogger(JobTaskServiceImpl.class);

    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;

    @Autowired
    private BaseDao baseDao;

    @PostConstruct
    public void init() throws Exception {
        List<ScheduleJob> jobList = getAllTask();
        for (ScheduleJob job : jobList) {
            addJob(job);
        }
    }

    /**
     * 获取所有定时任务
     *
     * @return
     */
    @Override
    public List<ScheduleJob> getAllTask() throws Exception {
        String sql = "SELECT * FROM t_schedule_job ";
        List<ScheduleJob> jobList = baseDao.findList(ScheduleJob.class, sql);

        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        TriggerKey triggerKey;
        CronTrigger trigger;

        for (ScheduleJob job : jobList) {
            triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
            trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

            job.setTriggerState(scheduler.getTriggerState(triggerKey).toString());
        }
        return jobList;
    }

    /**
     * 根据Id获取定时任务对象
     */
    @Override
    public ScheduleJob getTaskById(String jobId) throws Exception {
        if (StringUtils.isBlank(jobId)) {
            return null;
        }
        String sql = " SELECT * FROM t_schedule_job WHERE id = ? ";
        return baseDao.findFirst(ScheduleJob.class, sql, jobId);
    }

    /**
     * 新增定时任务
     *
     * @param scheduleJob
     * @return
     */
    @Override
    public int addTask(ScheduleJob scheduleJob) throws Exception {
        String sql = "INSERT INTO t_schedule_job(spring_id, job_name, job_group, description, cron_expression, bean_class, method_name, is_concurrent" +
                ", job_status, warn_time, create_time) VALUES(?,?,?,?,?,?,?,?,?,?,?)";
        List<Object> params = new ArrayList<>();
        params.add(scheduleJob.getSpringId());
        params.add(scheduleJob.getJobName());
        params.add(scheduleJob.getJobGroup());
        params.add(scheduleJob.getDescription());
        params.add(scheduleJob.getCronExpression());
        params.add(scheduleJob.getBeanClass());
        params.add(scheduleJob.getMethodName());
        params.add(scheduleJob.getIsConcurrent());
        params.add(scheduleJob.getJobStatus());
        params.add(scheduleJob.getWarnTime());
        params.add(new Date());
        return baseDao.execute(sql, params.toArray());
    }

    /**
     * 更改任务状态
     */
    @Override
    public void updateStatus(String jobId, String jobStatus) throws Exception {
        ScheduleJob job = getTaskById(jobId);
        if (job == null) {
            return;
        }
        if (Constants.JOB_CONCURRENT_NOT.equals(jobStatus)) {
            deleteJob(job);
            job.setJobStatus(Constants.JOB_STATUS_NOT_RUNNING);
            WebUtil.removeBlockTaskBySpringId(job.getSpringId());

        } else if (Constants.JOB_CONCURRENT_IS.equals(jobStatus)) {
            job.setJobStatus(Constants.JOB_STATUS_RUNNING);
            addJob(job);

        }
        String sql = " UPDATE t_schedule_job SET job_status = ? WHERE id = ? ";
        baseDao.execute(sql, new Object[]{jobStatus, jobId});
    }

    /**
     * 更改任务 cron表达式
     */
    @Override
    public void updateCron(String jobId, String cron) throws Exception {
        ScheduleJob job = getTaskById(jobId);
        if (job == null) {
            return;
        }
        job.setCronExpression(cron);
        if (Constants.JOB_STATUS_RUNNING.equals(job.getJobStatus())) {
            updateJobCron(job);
        }
        String sql = " UPDATE t_schedule_job SET cron_expression = ? WHERE id = ? ";
        baseDao.execute(sql, new Object[]{cron, jobId});
    }

    /**
     * 更改任务 预警时间
     */
    @Override
    public void updateWarnTime(String jobId, String warnTime) throws Exception {
        ScheduleJob job = getTaskById(jobId);
        if (job == null) {
            return;
        }
        String sql = " UPDATE t_schedule_job SET warn_time = ? WHERE id = ? ";
        baseDao.execute(sql, new Object[]{warnTime, jobId});

    }

    /**
     * 添加任务（添加任务到定时器中，不是添加到数据库）
     */
    @Override
    public void addJob(ScheduleJob job) throws Exception {
        if (job == null || !Constants.JOB_STATUS_RUNNING.equals(job.getJobStatus())) {
            return;
        }
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        log.debug(scheduler + ".......................................................................................add");
        TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());

        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

        // 不存在，创建一个
        if (null == trigger) {
            Class clazz = Constants.JOB_CONCURRENT_IS.equals(job.getIsConcurrent()) ? QuartzJobFactory.class : QuartzJobFactoryDisallowConcurrentExecution.class;

            JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup()).build();

            jobDetail.getJobDataMap().put("sdRepay", job);

            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());

            trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup()).withSchedule(scheduleBuilder).build();

            scheduler.scheduleJob(jobDetail, trigger);
        } else {
            // Trigger已存在，那么更新相应的定时设置
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());

            // 按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

            // 按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);
        }
    }

    /**
     * 暂停一个job
     *
     * @param scheduleJob
     */
    @Override
    public void pauseJob(ScheduleJob scheduleJob) throws Exception {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
        scheduler.pauseJob(jobKey);
    }

    /**
     * 恢复一个job
     *
     * @param scheduleJob
     */
    @Override
    public void resumeJob(ScheduleJob scheduleJob) throws Exception {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
        scheduler.resumeJob(jobKey);
    }

    /**
     * 删除一个job（删除定时器中的任务，不是删除数据库）
     *
     * @param scheduleJob
     */
    @Override
    public void deleteJob(ScheduleJob scheduleJob) throws Exception {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
        scheduler.deleteJob(jobKey);

    }

    /**
     * 立即执行job
     *
     * @param scheduleJob
     */
    @Override
    public void runAJobNow(ScheduleJob scheduleJob) throws Exception {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
        scheduler.triggerJob(jobKey);
    }

    /**
     * 更新job时间表达式
     *
     * @param scheduleJob
     */
    public void updateJobCron(ScheduleJob scheduleJob) throws SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();

        TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());

        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());

        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

        scheduler.rescheduleJob(triggerKey, trigger);
    }


    /**
     * 停止一个job
     *
     * @param scheduleJob
     */
    @Override
    public void stopJob(ScheduleJob scheduleJob) throws Exception {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
        scheduler.unscheduleJob(triggerKey);
    }
}
